package com.juzipi.framework.web.service;

import com.auth0.jwt.interfaces.DecodedJWT;
import com.juzipi.common.constant.Constants;
import com.juzipi.common.utils.StringUtils;
import com.juzipi.common.utils.jwt.JWTUtils;
import com.juzipi.common.utils.redis.RedisUtils;
import com.juzipi.common.utils.uuid.IdUtils;
import com.juzipi.inter.domain.LoginUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Component
public class TokenService {

    //token自定义标识
    @Value("${token.header}")
    private String header;
    //密钥,盐
    @Value("${token.secret")
    private String secret;
    //有效时间
    @Value("${token.expireTime}")
    private int expireTime;

    protected static final long MILLIS_SECOND = 1000;//秒

    protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;//分钟

    private static final long MILLIS_MINUTE_TEN = 10 * 60 * 1000;//十分钟


    @Autowired
    private RedisUtils redisUtils;


    /**
     * 获取用户身份信息
     * @param request
     * @return
     */
    public LoginUser getLoginUser(HttpServletRequest request){
        if (StringUtils.isNull(request)){
            return null;
        }
        String token = getToken(request);
        if (StringUtils.isNotNull(token)){
            //验证并解析token
            DecodedJWT verify = JWTUtils.verify(token,secret);
            //解析token获取荷载里的键
            String uuid = verify.getClaim(Constants.LOGIN_USER_KEY).asString();
            //因为redis里存的是 LOGIN_USER_KEY + 用户的uuid组合的key
            String userKey = getTokenKey(uuid);
            //然后查redis得到 loginUser
            return redisUtils.getCacheObject(userKey);
        }
        return null;
    }



    /**
     * 设置用户身份信息
     * @param loginUser
     */
    public void setLoginUser(LoginUser loginUser){
        if (StringUtils.isNotNull(loginUser) && StringUtils.isNotEmpty(loginUser.getUuid())){
            refreshToken(loginUser);
        }
    }


    /**
     * 删除用户身份信息
     * @param uuid
     */
    public void delLoginUser(String uuid){
        if (StringUtils.isNotEmpty(uuid)){
            //根据用户的uuid获取到用户在redis中的key
            String userKey = getTokenKey(uuid);
            redisUtils.deleteObject(userKey);
        }
    }


    /**
     * 验证令牌有效期，相差10分钟就自动刷新
     * @param loginUser
     */
    public void verifyToken(LoginUser loginUser){
        //用户的过期时间时间
        Long expireTime = loginUser.getExpireTime();
        //系统当前时间
        long currentTime = System.currentTimeMillis();
        if (expireTime - currentTime <= MILLIS_MINUTE_TEN){
            refreshToken(loginUser);
        }
    }

    /**
     * 获取请求头中的token
     * @param request
     * @return
     */
    private String getToken(HttpServletRequest request){
        return request.getHeader(header);
    }


    /**
     * 创建token，给荷载添加信息
     * @param loginUser
     * @return
     */
    public String createToken(LoginUser loginUser){
        //生成uuid
        String uuid = IdUtils.fastUUID();
        //设置给登录用户
        loginUser.setUuid(uuid);
        //因为生成的token没有过期时间，所以调用刷新的方法，它就加上了过期时间
        refreshToken(loginUser);
        //设置荷载
        LinkedHashMap<String, String> claims = new LinkedHashMap<>();
        //荷载是把 存入redis的key 拆开分别为荷载的 key 和 value
        claims.put(Constants.LOGIN_USER_KEY,uuid);
        return generateToken(claims);
    }


    /**
     * 生成token，用jwt生成token
     * @param claims
     * @return
     */
    private String generateToken(Map<String,String> claims){
        //荷载和密钥
        return JWTUtils.getToken(claims, secret);
    }


    /**
     * 刷新token有效期
     * @param loginUser
     */
    private void refreshToken(LoginUser loginUser) {
        loginUser.setLoginTime(System.currentTimeMillis());
        //设置过期时间是，登陆时间加token有效时间
        loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);//分钟
        //根据uuid将loginUser缓存
        String userKey = getTokenKey(loginUser.getUuid());
        //存入redis (key 值 过期时间 时间单位)
        redisUtils.setCacheObject(userKey,loginUser,expireTime, TimeUnit.MINUTES);
    }


    /**
     * 获取登录用户生成的uuid，作为token的key，具体为前缀 + uuid
     * @param uuid 这个是保存在登录用户信息里的
     * @return
     */
    private String getTokenKey(String uuid){
        //这个是存入redis的key
        return Constants.LOGIN_USER_KEY + uuid;
    }

}
